#include "alarmdialog.h"
#include "dbtools.h"
#include "exchangetagentity.h"
#include <iostream>
#include <QSqlQuery>
#include <windows.h>

ExchangeTagEntity::ExchangeTagEntity(QObject *parent, int tempExchangeTagId,
                                     QString tempExchangeTagName, QString tempExchangeTagTag,
                                     QString tempExchangeTagDesc, double tempReal,
                                     const QSqlDatabase * sqliteConnection, const QSqlDatabase * sqlServerConnection)
    :exchangeTagId(tempExchangeTagId), exchangeTagName(tempExchangeTagName),
      exchangeTagTag(tempExchangeTagTag), exchangeTagDesc(tempExchangeTagDesc),
      real(tempReal), threadSqliteConnection(*sqliteConnection), threadSqlServerConnection(*sqlServerConnection)
{
//    connect(this, &ExchangeTagEntity::realValueChangeToOne, this, &ExchangeTagEntity::doCalculation);
}

int ExchangeTagEntity::getExchangeTagId() const
{
    return exchangeTagId;
}

void ExchangeTagEntity::setExchangeTagId(int newExchangeTagId)
{
    exchangeTagId = newExchangeTagId;
}

const QString &ExchangeTagEntity::getExchangeTagName() const
{
    return exchangeTagName;
}

void ExchangeTagEntity::setExchangeTagName(const QString &newExchangeTagName)
{
    exchangeTagName = newExchangeTagName;
}

const QString &ExchangeTagEntity::getExchangeTagTag() const
{
    return exchangeTagTag;
}

void ExchangeTagEntity::setExchangeTagTag(const QString &newExchangeTagTag)
{
    exchangeTagTag = newExchangeTagTag;
}

const QString &ExchangeTagEntity::getExchangeTagDesc() const
{
    return exchangeTagDesc;
}

void ExchangeTagEntity::setExchangeTagDesc(const QString &newExchangeTagDesc)
{
    exchangeTagDesc = newExchangeTagDesc;
}

//double ExchangeTagEntity::getReal() const
//{
//    return real;
//}

/*
 * 在这里采用监测数据改变的机制，类似vue的watch机制，来发出signal的，也就是说，我系统的上一级操作是
 * 不停的监测数据库交换表格的最后一列，TOP查询，并且将这个结果更新到class来，只要我监测到最新的值和
 * 之前的值不相等，并且最新的值是1，也就是说明交换信号从0变为1，则我认为交换发生，开始进行计算
*/
//void ExchangeTagEntity::setReal(double newReal)
//{
//    if (newReal != real && 1.0 == newReal) {
//            real = newReal;
//            emit realChanged(newReal);
//        } else {
//        real = newReal;
//    }
//}

//void ExchangeTagEntity::doCalculation()
//{
//    std::cout << "detect exchange happening..." << std::endl;
////    Sleep(5000); // 这里好奇怪，首先他确实执行了，但是并没有阻塞当前线程，扫描还在
//    std::cout << "calculating..." << std::endl;
//}

double ExchangeTagEntity::getReal() const
{
    return real;
}

void ExchangeTagEntity::setReal(double newReal)
{
    /*
     * 这里采用的是如果新值和旧值不相等，并且新值为1.0，就可以认为是从0-1的变化，认为发生了交换
    */
    if (real != newReal && newReal == 1.0) {
        real = newReal;
        emit realChanged();
    } else {
        real = newReal;
    }
}

void ExchangeTagEntity::realChanged()
{
    std::cout << "detect exchange happening... real = " << real << exchangeTagTag.toStdString() <<std::endl;
//    Sleep(1000); // 这里好奇怪，首先他确实执行了，但是并没有阻塞当前线程，扫描还在
    std::cout << "calculating..." << std::endl;

    // 用来存储交换信号的五小时之内处于正在交换状态的时间序列
    QMap<QDateTime, double> cycleMap = DBTools::getUnderlineTagTimeSeris(threadSqlServerConnection,
                                                                          QDateTime::currentDateTime().addSecs(-60*60*5.1),
                                                                          QDateTime::currentDateTime(),getExchangeTagTag(),
                                                                          "JHX_DATA", "", " and " + getExchangeTagTag() + "=1"); //*60*1
    /*
     * 到这里，resultMap拿到，<QDateTime, double>,<QDateTime, double>......
     * 然后要在这里，便利，寻找到四个节点
    */
    QList<QDateTime> cycleTimeList;  // 用来将Map数据转换为List<QDateTime>拿到时间列表
    QList<QDateTime> cycleStartTimeList;  // 用来存储从当前时间向前数有效的节点时间，即五次交换开始时间
    QMap<QDateTime, double>::ConstIterator iter = cycleMap.constBegin();

    while(iter != cycleMap.constEnd()) {
        cycleTimeList.append(iter.key());
        ++iter;
    }

    for(int index=0;index<cycleTimeList.size()-1;++index) {
        if(cycleTimeList[index].addSecs(15*60) < cycleTimeList[index+1]) {
            cycleStartTimeList.append(cycleTimeList[index+1]);
        }
    }

    /*从sqlite数据里的全局参数配置里，获取dtw算法的阈值*/
    QSqlQuery dtwRangeQuery(threadSqliteConnection);
    QString dtwQuery = "select dtw_error_range from global_setting";
    dtwRangeQuery.exec(dtwQuery);
    dtwRangeQuery.next();
    double dtwRange = dtwRangeQuery.value(0).toDouble();

    /*获取当前测温点的四轮温度数据，前三轮取均值，第四轮算时间翘曲 tag_area, tag_regenerator_no+"号燃烧室", tag_name*/
    QSqlQuery query(threadSqliteConnection);
    QString selectQuery = "select tag_code, tag_area, tag_regenerator_no, tag_name from tag where tag_involve_calculation = \"1\" "
                          "and tag_exchange = (select exchange_tag_name from exchange_tag where "
                          "exchange_tag_tag = \"" + exchangeTagTag +  "\")";
    query.exec(selectQuery);

    while(query.next()) {
        QList<QList<double>> timeSerisMatrix;
//        qDebug() << query.value(0); value(0)->tag_code, value(1)->tag_area, value(2)->tag_regenerator_no, value(3)->tag_name
        for(int round=0; round < cycleStartTimeList.size()-1; ++round) {
            // TODO: 这里已经采用测试数据了，AMT表格，正常应该采用实际表格名称，BFMT_DATA之类的，而且这里证明查询是明显需要时间的
            timeSerisMatrix.append(DBTools::getUnderlineTagTimeSeris(threadSqlServerConnection, cycleStartTimeList[round],
                                                                     cycleStartTimeList[round+1], query.value(0).toString(), "AMT_DATA", "", "").values());
        }

        if(dtwRange < DBTools::calculateDTW(timeSerisMatrix)) {
            /*
             * 将报警事件写入event表格，将tag表里该点是否参与计算置1.0，弹窗报警
             * TODO: 这里是要做弹窗警告的，做DTW算法核心
            */
            QSqlQuery writeQuery(threadSqliteConnection);
            writeQuery.exec("insert into event ( alarm_event_tag_code, alarm_event_tag_area, alarm_event_tag_regenerator_no, "
                            "alarm_event_timestamp) values ( '" + query.value(0).toString() + "', '" + query.value(1).toString() + "', '" +
                            query.value(2).toString() +  "', '" + QDateTime::currentDateTime().toString(Qt::ISODate)+"');");
            writeQuery.exec("UPDATE tag SET tag_involve_calculation = '1' WHERE tag_code = '" + query.value(0).toString() + "';");
            AlarmDialog * alarmDialog = new AlarmDialog(nullptr, query.value(3).toString(), query.value(1).toString(), query.value(2).toString());
            alarmDialog->show();
        }
    }

    Sleep(1000);
    setReal(0.0);
    std::cout << "set real back to: " << real <<  std::endl;
}
